Hook.Add("chatMessage", "monsterChat", function (message, client)
	if CLIENT then return end
    if (string.sub(message, 1, 1) == '/') or (client.Character == nil) or (not isCharacterMonster(client.Character)) or (client.Character.IsDead) then return end
	
	for player in Client.ClientList do
		if (player == client) or (player.Character == nil) or (player.Character.IsDead) then
			messageClient(player, 'chat-regular', message, tostring(client.Character.SpeciesName) .. ' (' .. client.Name .. ')')
			--messageClient(player, 'chat-regular', message, client.Character.Name)
		elseif player.Character.CanHearCharacter(client.Character) then
			messageClient(player, 'chat-regular', message, tostring(client.Character.SpeciesName) .. ' (' .. client.Name .. ')')
		elseif isCharacterMonster(player.Character) then
			messageClient(player, 'chat-monster', message, tostring(client.Character.SpeciesName) .. ' (' .. client.Name .. ')')
		end
	end

    return true
end)

-- User Commands
-- Lists and explains user commands
Hook.Add("chatMessage", "helpCommand", function (message, client)
    if message ~= '/help' then return end
	
	local text = ''
	if not Game.RoundStarted then text = text .. '\n' end
	
	text = text .. '-玩家命令-\n'
	text = text .. '/help - 查看命令列表\n'
	text = text .. '/vote - 开启游戏模式投票\n'
	text = text .. '/admin - 引起管理员注意\n'
	text = text .. '/admin <text> - 发送消息给管理员\n'
	text = text .. '/players - 查看所有玩家以及他们扮演的角色\n'
	text = text .. '/tickets - 查看JET和MERCS入场券数量\n'
	text = text .. '/decon - 查看设施净化剩余时间\n'
	text = text .. '/gamemodes - 查看所有游戏模式\n'
	text = text .. '/gamemode - 查看当前模式的数据\n'
	text = text .. '/gamemode <name> - 查看指定模式的数据\n'
	if client.HasPermission(ClientPermissions.ConsoleCommands) then
		text = text .. '-管理员命令-\n'
		text = text .. '/spectator - 成为观看者\n'
		text = text .. '/spectator <player> - 使指定玩家成为观看者\n'
		text = text .. '/spectators - 查看所有观看者\n'
		text = text .. '/vote <arguments> - 开启投票\n'
		text = text .. '/cfg <arguments> - 配置模组\n'
	end
	
	text = text .. '-命令查询完毕-'
	
	messageClient(client, 'text-command', text)

    return true
end)

-- Communicate with admin
Hook.Add("chatMessage", "callAdmin", function (message, client)
    if string.sub(message, 1, 7) ~= '/admin ' and message ~= '/admin' then return end
	
	local text = ''
	if not Game.RoundStarted then text = text .. '\n' end
	
	if #message < 8 then
		text = '玩家 ' .. client.Name .. ' 正在呼叫管理员和主持人'
	else 
		text = '玩家 ' .. client.Name .. ' 向管理员和主持人发送消息：' .. string.sub(message, 8)
	end
	
	for clientOther in Client.ClientList do
		if clientOther.HasPermission(ClientPermissions.ConsoleCommands) then
			messageClient(clientOther, 'text-command', text)
		end
	end

    return true
end)

-- Gives a list of players alive
Hook.Add("chatMessage", "livePlayerList", function (message, client)
    if message ~= '/players' then return end
	
	local text = ''
	if not Game.RoundStarted then text = text .. '\n' end
	
	text = text .. '-玩家列表-\n'
	
	for player in Client.ClientList do
		if player.Character ~= nil and not player.Character.IsDead then
			if player.Character.SpeciesName == 'human' then
				if isCharacterTerrorist(player.Character) and isCharacterCivilian(player.Character) then
					text = text .. player.Name .. ' 是T阵营的文职成员\n'
				elseif isCharacterTerrorist(player.Character) then
					text = text .. player.Name .. ' 是T阵营的武装成员\n'
				elseif isCharacterNexpharma(player.Character) and isCharacterCivilian(player.Character) then
					text = text .. player.Name .. ' 是Nex制药公司的文职成员\n'
				elseif isCharacterNexpharma(player.Character) then
					text = text .. player.Name .. ' 是Nex制药公司的武装成员\n'
				end
			elseif player.Character.SpeciesName == 'Mantisadmin' then
				text = text .. player.Name .. ' 是变异螳螂\n'
			elseif player.Character.SpeciesName == 'Crawleradmin' then
				text = text .. player.Name .. ' 是变异藻爬\n'
			elseif player.Character.SpeciesName == 'Humanhusk' then
				text = text .. player.Name .. ' 是感染体\n'
			elseif player.Character.SpeciesName == 'Humangoblin' then
				text = text .. player.Name .. ' 是哥布林\n'
			elseif player.Character.SpeciesName == 'Humantroll' then
				text = text .. player.Name .. ' 是巨魔\n'
			end
		end
	end
	
	text = text .. '-END OF LIST-'
	
	messageClient(client, 'text-command', text)

    return true
end)

function respawnInfo(client, msgType)
	if (FG.terroristTickets >= 1) or (FG.nexpharmaTickets >= 1) or (FG.settings.respawnSpeed == 0) then
		messageClient(client, msgType or 'text-game', '重生： ' .. FG.respawnETA .. '.')
	else
		messageClient(client, msgType or 'text-game', '无入场券，无法重生。')
	end
end

-- Tells the current amount of tickets and time to respawn
Hook.Add("chatMessage", "respawnInfo", function (message, client)
    if message ~= '/tickets' and message ~= '/respawn' then return end
	if not Game.RoundStarted then
		messageClient(client, 'text-command', '\n巡回还未开始。')
		return true
	end
	
	local text = ''
	
	text = text .. 'T阵营拥有 ' .. FG.terroristTickets .. ' 张入场券。\n'
	text = text .. 'Nex制药公司拥有 ' .. FG.nexpharmaTickets .. ' 张入场券。\n'
	text = text .. "入场券数最多的队伍将会优先重生。"
	respawnInfo(client, 'text-command')
	
	messageClient(client, 'text-command', text)

    return true
end)

-- Tells the user time until decontamination
Hook.Add("chatMessage", "deconInfo", function (message, client)
    if message ~= '/decon' then return end
	if not Game.RoundStarted then
		messageClient(client, 'text-command', '\n巡回还未开始。')
		return true
	end
	
	if FG.decontaminationTimer <= 0 then
		messageClient(client, 'text-command', '设施净化已初始化。')
	else
		messageClient(client, 'text-command', '设施净化时间：' .. numberToTime(FG.decontaminationTimer, 1))
	end

    return true
end)

-- Lists all the gamemodes (is like "/cfg plist" but for clients)
Hook.Add("chatMessage", "listgamemodes", function (message, client)
    if message ~= '/gamemodes' then return end
	
	text = ''
	if not Game.RoundStarted then text = text .. '\n' end
	
	for presetName, presetSettings in pairs(FG.settingsPresets) do
		local author = '[UNKNOWN]'
		if presetSettings.author ~= nil then
			author = presetSettings.author
		end
		local info = '没有提供任何信息。'
		if presetSettings.info ~= nil then
			info = presetSettings.info
		end
		text = text .. '"' .. presetName .. '"' .. ' by ' .. author .. ' - ' .. info ..'\n\n'
	end
	messageClient(client, 'text-command', string.sub(text, 1, #text - 2))

    return true
end)

-- Gives data on a specific gamemode (is like "/cfg pview" or "/cfg list" but for clients)
Hook.Add("chatMessage", "viewgamemode", function (message, client)
    if string.sub(message, 1, 10) ~= '/gamemode ' and message ~= '/gamemode' then return end
	
	text = ''
	if not Game.RoundStarted then text = text .. '\n' end
	
	if message == '/gamemode' then
		text = text .. table.print(FG.settings, true, true)
		messageClient(client, 'text-command', text)
	elseif not FG.settingsPresets[string.sub(message, 11, #message)] then
		text = text .. '没有名为 ' .. string.sub(message, 11, #message) .. ' 的游戏模式。请发送 /gamemodes 获取游戏模式列表。'
		messageClient(client, 'text-command', text)
	else
		text = text .. table.print(FG.settingsPresets[string.sub(message, 11, #message)], true, true)
		messageClient(client, 'text-command', text)
	end

    return true
end)

-- Declare self as Spectator (ADMIN ONLY)
Hook.Add("chatMessage", "toggleSpectator", function (message, client)
    if string.sub(message, 1, 11) ~= '/spectator ' and message ~= '/spectator' then return end
	if not client.HasPermission(ClientPermissions.ConsoleCommands) then messageClient(client, 'text-warning', '需要控制台权限！') return true end
	
	local text = ''
	if not Game.RoundStarted then text = text .. '\n' end
	
	if message == '/spectator' then
		if FG.spectators[client.Name] then
			FG.spectators[client.Name] = nil
		else
			FG.spectators[client.Name] = true
		end
		text = text .. '你' .. (FG.spectators[client.Name] and '在' or '不在') .. '观看者列表中'
	else
		if not findClientByUsername(string.sub(message, 12)) then 
			text = text .. '在大厅中没有找到该玩家'
			return true
		end
		if FG.spectators[client.Name] then
			FG.spectators[client.Name] = nil
		else
			FG.spectators[client.Name] = true
		end
		FG.spectators[string.sub(message, 12)] = not FG.spectators[string.sub(message, 12)]
		text = text .. '目前' .. string.sub(message, 12) .. (FG.spectators[string.sub(message, 12)] and '在' or '不在') .. '观看者列表中'
	end
	
	messageClient(client, 'text-command', text)

    return true
end)

-- Declare self as Spectator (ADMIN ONLY)
Hook.Add("chatMessage", "listSpectator", function (message, client)
    if message ~= '/spectators' then return end
	if not client.HasPermission(ClientPermissions.ConsoleCommands) then messageClient(client, 'text-warning', '需要控制台权限！') return true end
	
	local noSpectators = true
	local text = ''
	if not Game.RoundStarted then text = text .. '\n' end
	
	text = text .. '-观看者列表-\n'
	
	for player, value in pairs(FG.spectators) do 
		if value then
			text = text .. player .. ' 在观看者列表中。\n'
			noSpectators = false
		end
	end
	
	text = text .. '-结束-'
	
	if noSpectators then
		messageClient(client, 'text-command', '\n没有任何观看者。')
	else
		messageClient(client, 'text-command', text)
	end
	
    return true
end)

-- Cast a vote
Hook.Add("chatMessage", "democracyCastVote", function (message, client)
	if table.has(FG.democracy.voters, client) or (not table.has(FG.democracy.options, message)) or (not FG.democracy.started) then return end
	
	local text = ''
	if not Game.RoundStarted then text = text .. '\n' end
	
	FG.democracy.votes[client] = message
	table.insert(FG.democracy.voters, client)
	
	messageClient(client, 'text-general', '你的投票 “' .. message .. '” 已被丢弃并无法改变！')
	
	for player in Client.ClientList do
		messageClient(player, 'text-general', '当前已有 ' .. tostring(#FG.democracy.voters) .. ' ／ ' .. tostring(#Client.ClientList) .. ' 的玩家参与了投票。')
	end
	
	if (#Client.ClientList - #FG.democracy.voters) <= 0 then
		FG.democracy.endVoting(Client.ClientList)
	end
	
	return true
end)

-- Starts a vote (ADMIN ONLY)
Hook.Add("chatMessage", "democracyInterface", function (message, client)
	if string.sub(message, 1, 5) ~= '/vote' and message ~= '/vote' then return end
	if Game.RoundStarted then messageClient(client, 'text-warning', "不能在进行巡回的过程中开启投票") return true end
	
	local text = ''
	if not Game.RoundStarted then text = text .. '\n' end
	
	-- Vote command for clients who aren't admins
	if (not client.HasPermission(ClientPermissions.ConsoleCommands)) or (message == '/vote asclient') then
		-- Gamemode vote has already been done
		if FG.democracy.gamemodeChosen then
			messageClient(client, 'text-warning', '游戏模式投票已结束！')
		elseif FG.democracy.started then
		-- If voting has started, repeat announcement to client
			-- Do counting
			local voteCount = {}
			-- Get all options
			for option in FG.democracy.options do
				voteCount[option] = 0
			end
			-- Count the votes
			for vote in FG.democracy.votes do
				voteCount[vote] = voteCount[vote] + 1
			end
			-- Put text together
			text = text .. '在聊天框输入下方选项之一进行投票：'
			for option in FG.democracy.options do
				text = text .. option .. ' 拥有 ' .. tostring(voteCount[option]) .. ' 票，'
			end
			text = string.sub(text, 1, #text - 2) .. '.'
			messageClient(client, 'text-command', text)
		-- Start poll and announce it to all
		else
			FG.democracy.options = {}
			FG.democracy.votes = {}
			FG.democracy.voters = {}
			FG.democracy.started = true
			FG.democracy.gamemode = true
			FG.democracy.gamemodeChosen = false
			text = text .. '民主时间！请为其中之一进行投票：'
			for presetName, presetSettings in pairs(FG.settingsPresets) do
				text = text .. presetName .. ', '
				table.insert(FG.democracy.options, presetName)
			end
			text = string.sub(text, 1, #text - 2) .. '.\n在聊天框中输入你意向的投票选项'
			for player in Client.ClientList do
				messageClient(player, 'text-command', text)
			end
		end
		return true
	end
	
	-- Breaks down message into words
	local msgTxt = message
	local words = {}
	local word = ''
	local letter = ''
	for count = 1, #msgTxt do
		letter = string.sub(msgTxt, count, count)
		if (letter ~= ' ') or (count == #msgTxt) then
			word = word .. letter
		end
		if ((letter == ' ') or (count == #msgTxt)) and (word ~= '') then
			table.insert(words, word)
			word = ''
		end
	end
	
	-- Remove the first word (which should be /democracy)
	table.remove(words, 1)
	
	-- Joins all words after an index
	local function joinAllWordsAfterIndex (index, spacing)
		local joined = ''
		for n = index, #words do
			joined = joined .. table.remove(words, index) .. string.rep(' ', spacing or 0)
		end
		joined = string.sub(joined, 1, #joined - spacing)
		words[index] = joined
	end
	
	-- Lists commands
	if words[1] == 'help' then
		text = text .. '-投票命令-\n'
		text = text .. '/vote help - 查看投票帮助\n'
		text = text .. '/vote asclient - the client /vote for admins.\n'
		text = text .. '/vote allgamemode <options> - 为所有的游戏模式开启投票\n'
		text = text .. '/vote gamemodes <options> - 为某些游戏模式开启投票\n'
		text = text .. '/vote start <options> - 开启并宣布投票。\n'
		text = text .. '/vote repeat - 重复投票公告。\n'
		text = text .. '/vote end - 结束投票并统计票数\n'
		text = text .. '-结束-'
		messageClient(client, 'text-command', text)
	-- Starts a poll with the options being all the gamemodes
	elseif words[1] == 'allgamemodes' then
		if FG.democracy.started then messageClient(client, 'text-warning', '投票已经开始了， 发送 "/vote end"。') return true end
		FG.democracy.options = {}
		FG.democracy.votes = {}
		FG.democracy.voters = {}
		FG.democracy.started = true
		FG.democracy.gamemode = true
		FG.democracy.gamemodeChosen = false
		table.remove(words, 1)
		text = text .. '民主时间！请为其中之一进行投票：'
		for presetName, presetSettings in pairs(FG.settingsPresets) do
			text = text .. presetName .. ', '
			table.insert(FG.democracy.options, presetName)
		end
		text = string.sub(text, 1, #text - 2) .. '.\n在聊天框中输入你意向的投票选项。'
		for player in Client.ClientList do
			messageClient(player, 'text-command', text)
		end
	-- Starts a poll with the options being some gamemodes
	elseif words[1] == 'gamemodes' then
		if FG.democracy.started then messageClient(client, 'text-warning', '投票已经开始了， 发送 "/vote end"。') return true end
		FG.democracy.options = {}
		FG.democracy.votes = {}
		FG.democracy.voters = {}
		FG.democracy.started = true
		FG.democracy.gamemode = true
		FG.democracy.gamemodeChosen = false
		table.remove(words, 1)
		text = text .. '民主时间！请为其中之一进行投票：'
		for presetName, presetSettings in pairs(FG.settingsPresets) do
			if table.has(words, presetName) then
				text = text .. presetName .. ', '
				table.insert(FG.democracy.options, presetName)
			end
		end
		text = string.sub(text, 1, #text - 2) .. '.\n在聊天框中输入你意向的投票选项。'
		for player in Client.ClientList do
			messageClient(player, 'text-command', text)
		end
	-- Starts a poll and notifies clients of options
	elseif words[1] == 'start' then
		if FG.democracy.started then messageClient(client, 'text-warning', '投票已经开始了， 发送 "/vote end"。') return true end
		FG.democracy.options = {}
		FG.democracy.votes = {}
		FG.democracy.voters = {}
		FG.democracy.started = true
		FG.democracy.gamemode = false
		table.remove(words, 1)
		text = text .. '民主时间！请为其中之一进行投票：'
		for word in words do
			text = text .. word .. ', '
			table.insert(FG.democracy.options, word)
		end
		text = string.sub(text, 1, #text - 2) .. '.\n在聊天框中输入你意向的投票选项。'
		for player in Client.ClientList do
			messageClient(player, 'text-command', text)
		end
	-- Repeats the warning
	elseif words[1] == 'repeat' then
		if not FG.democracy.started then messageClient(client, 'text-warning', '投票未开始') return true end
		text = text .. '在聊天框输入下方选项之一进行投票：'
		for option in FG.democracy.options do
			text = text .. option .. ', '
		end
		text = string.sub(text, 1, #text - 2) .. '.\n在聊天框中输入你意向的投票选项。'
		for player in Client.ClientList do
			messageClient(player, 'text-command', text)
		end
	-- Ends a poll and shares poll results
	elseif words[1] == 'end' then
		if not FG.democracy.started then messageClient(client, 'text-warning', '投票未开始') return true end
		FG.democracy.endVoting(Client.ClientList)
	-- Invalid command
	elseif (message == '/vote') or (message == '/vote ') then
		text = text .. '发送 "/vote help" 查看投票帮助'
		messageClient(client, 'text-command', text)
	else
		text = text .. ' 是无效的命令！请发送 "/vote help" 查看投票帮助'
		messageClient(client, 'text-warning', text)
	end
	
	return true
end)

-- Settings interface (ADMIN ONLY)
Hook.Add("chatMessage", "settingsInterface", function (message, client)
    if string.sub(message, 1, 4) ~= '/cfg' then return end
	if not client.HasPermission(ClientPermissions.ConsoleCommands) then messageClient(client, 'text-warning', '需要控制台权限！') return true end
	
	local text = ''
	if not Game.RoundStarted then text = text .. '\n' end
	
	-- Breaks down message into words
	local msgTxt = message
	local words = {}
	local word = ''
	local letter = ''
	for count = 1, #msgTxt do
		letter = string.sub(msgTxt, count, count)
		if (letter ~= ' ') or (count == #msgTxt) then
			word = word .. letter
		end
		if ((letter == ' ') or (count == #msgTxt)) and (word ~= '') then
			table.insert(words, word)
			word = ''
		end
	end
	
	-- Remove the first word (which should be /cfg)
	table.remove(words, 1)
	
	-- Joins all words after an index
	local function joinAllWordsAfterIndex (index, spacing)
		local joined = ''
		for n = index, #words do
			joined = joined .. table.remove(words, index) .. string.rep(' ', spacing or 0)
		end
		joined = string.sub(joined, 1, #joined - spacing)
		words[index] = joined
	end
	
	-- Lists commands
	if words[1] == 'help' then
		text = text .. '-CFG 简易 命令-\n'
		text = text .. '/cfg help - 查看配置向导\n'
		text = text .. '/cfg list - 查看所有配置项\n'
		text = text .. '/cfg reset - 重置配置为默认\n'
		text = text .. '/cfg set <setting> <value> - 修改配置项\n'
		text = text .. '-CFG P 命令-\n'
		text = text .. '/cfg plist - 查看所有预设\n'
		text = text .. '/cfg preset - 重置所有预设\n'
		text = text .. '/cfg pload <preset> - 从预设读取配置\n'
		text = text .. '/cfg psave <preset> - 保存当前配置到预设\n'
		text = text .. '/cfg pdelete <preset> - 删除预设，操作无法回退\n'
		text = text .. '/cfg pview <preset> - 预览预设配置\n'
		text = text .. '-CFG R 命令-\n'
		text = text .. '/cfg rlist - 查看所有非管理员发送的预设\n'
		text = text .. '/cfg rload <username> - 读取非管理员发送的预设\n'
		text = text .. '/cfg rview <username> - 预览非管理员发送的预设\n'
		text = text .. '-结束-'
		messageClient(client, 'text-command', text)
	-- Lists keys and values
	elseif words[1] == 'list' then
		text = text .. table.print(FG.settings, true, true)
		messageClient(client, 'text-command', text)
	-- Resets settings to default
	elseif words[1] == 'reset' then
		FG.settings = table.copy(FG.settingsDefault)
		text = text ..  'Settings have been reset to default.'
		messageClient(client, 'text-command', text)
	-- Sets the value of a key
	elseif words[1] == 'set' then
		joinAllWordsAfterIndex(3, 1)
		if FG.settings[words[2]] ~= nil then
			if type(FG.settingsDefault[words[2]]) == 'boolean' then
				if (words[3] == 'true') and not FG.settings[words[2]] then
					FG.settings[words[2]] = true
					text = text .. table.print({[words[2]] = FG.settings[words[2]]}, true)
					messageClient(client, 'text-command', text)
				elseif (words[3] == 'false') and FG.settings[words[2]] then
					FG.settings[words[2]] = false
					text = text .. table.print({[words[2]] = FG.settings[words[2]]}, true)
					messageClient(client, 'text-command', text)
				elseif (words[3] ~= 'true') and (words[3] ~= 'false') then
					text = text .. '用户输入错误！'
					messageClient(client, 'text-warning', text)
				end
			elseif type(FG.settingsDefault[words[2]]) == 'number' then
				if tonumber(words[3]) ~= nil then
					FG.settings[words[2]] = tonumber(words[3])
					text = text .. table.print({[words[2]] = FG.settings[words[2]]}, true)
					messageClient(client, 'text-command', text)
				else
					text = text .. '用户输入错误！'
					messageClient(client, 'text-warning', text)
				end
			elseif type(FG.settingsDefault[words[2]]) == 'string' then
				FG.settings[words[2]] = words[3]
				text = text .. table.print({[words[2]] = FG.settings[words[2]]}, true)
				messageClient(client, 'text-command', text)
			elseif type(FG.settingsDefault[words[2]]) == 'table' then
				text = text .. 'Table类型的配置项只能通过预设改变。'
				messageClient(client, 'text-warning', text)
			end
		else
			text = text .. '用户输入错误！'
			messageClient(client, 'text-warning', text)
		end
	-- List presets
	elseif words[1] == 'plist' then
		for presetName, presetSettings in pairs(FG.settingsPresets) do
			local author = '【未知】'
			if presetSettings.author ~= nil then
				author = presetSettings.author
			end
			local info = '没有提供任何信息。'
			if presetSettings.info ~= nil then
				info = presetSettings.info
			end
			text = text .. '"' .. presetName .. '"' .. ' by ' .. author .. ' - ' .. info ..'\n\n'
		end
		messageClient(client, 'text-command', string.sub(text, 1, #text - 2))
	-- Resets settings presets
	elseif words[1] == 'preset' then
		joinAllWordsAfterIndex(2, 1)
		if (words[2] == 'yes i am sure') then
			FG.settingsPresets = table.copy(FG.settingsPresetsDefault)
			text = text ..  'Settings presets have been reset to default.'
			messageClient(client, 'text-command', text)
			-- Save changes to config file
			saveSettingsPresets()
		else
			text = text .. '请输入 "/cfg preset yes i am sure" 以确保您已意识到自己即将重置你的预设并保存为默认值，从而删除所有你配置的预设，该操作无法回退。'
			messageClient(client, 'popup', text)
		end
	-- Load a preset
	elseif words[1] == 'pload' then
		if FG.settingsPresets[words[2]] == nil then messageClient(client, 'text-warning', '预设不存在！') return true end
		joinAllWordsAfterIndex(2, 1)
		FG.settings = table.copy(FG.settingsDefault)
		for settingName, settingValue in pairs(FG.settingsPresets[words[2]]) do
			FG.settings[settingName] = settingValue
		end
		text = text .. table.print(FG.settings, true, true)
		messageClient(client, 'text-general', text)
	-- Saves to an existing preset
	elseif words[1] == 'psave' then
		joinAllWordsAfterIndex(2, 1)
		-- Only save all the settings that differ from the default
		local settingsPreset = {}
		for settingName, settingValue in pairs(FG.settings) do
			if FG.settingsDefault[settingName] ~= settingValue then
				settingsPreset[settingName] = settingValue
			end
		end
		-- Warn user if their preset doesn't change any settings
		if table.size(settingsPreset) == 0 then
			text = text .. '你的预设和默认配置相同！'
			messageClient(client, 'text-warning', text)
			text = ''
		end
		-- Make sure the setting exists and isn't a default preset
		if FG.settingsPresetsDefault[words[2]] then
			text = text .. words[2] .. ' 是默认预设并且无法覆盖。' 
			messageClient(client, 'text-warning', text)
		else
			FG.settingsPresets[words[2]] = settingsPreset
			text = text .. '你的预设已成功保存至 ' .. words[2] .. '.'
			messageClient(client, 'text-command', text)
		end
		-- Save changes to config file
		saveSettingsPresets()
	-- Delete a preset
	elseif (words[1] == 'pdelete') or (words[1] == 'premove') then
		joinAllWordsAfterIndex(2, 1)
		-- Make sure the setting exists and isn't a default preset
		if FG.settingsPresetsDefault[words[2]] then
			text = text .. words[2] .. ' 是默认预设并且无法删除。'
			messageClient(client, 'text-warning', text)
		elseif FG.settingsPresets[words[2]] then
			FG.settingsPresets[words[2]] = nil
			text = text .. '预设 ' .. words[2] .. ' 已被删除。'
			messageClient(client, 'text-command', text)
		else
			text = text .. '没有名为 ' .. words[2] .. ' 的预设'
			messageClient(client, 'text-warning', text)
		end
		-- Save changes to config file
		saveSettingsPresets()
	-- View a preset
	elseif words[1] == 'pview' then
		joinAllWordsAfterIndex(2, 1)
		text = text .. table.print(FG.settingsPresets[words[2]], true, true)
		messageClient(client, 'text-command', text)
	-- Lists received presets
	elseif words[1] == 'rlist' then
		for sender, settingsPresets in pairs(FG.settingsPresetsReceived) do
			local author = '[UNKNOWN]'
			if table.getValues(settingsPresets)[1].author ~= nil then
				author = table.getValues(settingsPresets)[1].author
			end
			local info = '没有提供任何信息。'
			if table.getValues(settingsPresets)[1].info ~= nil then
				info = table.getValues(settingsPresets)[1].info
			end
			text = text .. '"' .. table.getKeys(settingsPresets)[1] .. '"' .. ' by ' .. author .. ' - ' .. info ..'\n\n'
		end
		if (text == '') or (text == '\n') then
			text = text .. '还没有提交预设。\n\n'
		end
		messageClient(client, 'text-command', string.sub(text, 1, #text - 2))
	-- Loads a received preset
	elseif words[1] == 'rload' then
		if table.getValues(FG.settingsPresetsReceived[words[2]])[1] == nil then messageClient(client, 'text-warning', '预设不存在！') return true end
		joinAllWordsAfterIndex(2, 1)
		FG.settings = table.copy(FG.settingsDefault)
		for settingName, settingValue in pairs(table.getValues(FG.settingsPresetsReceived[words[2]])[1]) do
			FG.settings[settingName] = settingValue
		end
		text = text .. table.print(FG.settings, true, true)
		messageClient(client, 'text-command', text)
		-- Notifies client who sent the preset that it has been loaded
		local sender = findClientByUsername(words[2])
		if sender ~= nil then
			messageClient(sender, 'text-command', '你的预设配置已被服务器加载。')
		end
	-- Views a received preset
	elseif words[1] == 'rview' then
		joinAllWordsAfterIndex(2, 1)
		text = text .. table.print(table.getValues(FG.settingsPresetsReceived[words[2]])[1], true, true)
		messageClient(client, 'text-command', text)
	-- Invalid command
	elseif (message == '/cfg') or (message == '/cfg ') then
		text = text .. '发送 "/cfg help" 查看配置向导。'
		messageClient(client, 'text-command', text)
	else
		text = text .. ' 不是有效的命令！发送 "/cfg help" 查看配置向导。'
		messageClient(client, 'text-warning', text)
	end

    return true
end)

FG.loadedFiles['commands'] = true